/*
 * ! Ext JS Library 4.0 Copyright(c) 2006-2011 Sencha Inc. licensing@sencha.com
 * http://www.sencha.com/license
 */

/**
 * @class Ext.ux.desktop.Desktop
 * @extends Ext.panel.Panel
 *          <p>
 *          This class manages the wallpaper, shortcuts and taskbar.
 *          </p>
 */
Ext.define('Ext.ux.desktop.Desktop', {
    extend: 'Ext.panel.Panel',

    alias: 'widget.desktop',

    activeWindowCls: 'ux-desktop-active-win',
    inactiveWindowCls: 'ux-desktop-inactive-win',
    lastActiveWindow: null,

    border: false,
    html: '&#160;',
    layout: 'fitall',

    xTickSize: 1,
    yTickSize: 1,

    app: null,

    /**
    * @cfg {Array|Store} shortcuts The items to add to the DataView. This can
    *      be a {@link Ext.data.Store Store} or a simple array. Items should
    *      minimally provide the fields in the
    *      {@link Ext.ux.desktop.ShorcutModel ShortcutModel}.
    */
    //    shortcuts:     [
    //      {
    //          "Page": {
    //              "IconCss16": "databasel16",
    //              "IconCss24": "databasel24",
    //              "IconCss48": "databasel48",
    //              "IndexField": 0,
    //              "IsHide": false,
    //              "PageId": "/TestModule/Module1/Module1",
    //              "IsDisable": false,
    //              "Text": "测试模块一",
    //              "Parent": "faef4fe9-3c0e-4d9e-90e7-4b55b5280e87",
    //              "IsLeaf": true,
    //              "NodeLevel": 2,
    //              "Id": "c6007a2b-f903-44c7-ace5-7b22bf6d7940",
    //              "Version": 0,
    //              "CreateTime": new Date(
    //            1322293883161
    //          )
    //          },
    //          "PageId": "/TestModule/Module1/Module1",
    //          "IndexField": 0,
    //          "Id": "463ec268-164e-48f5-af02-f6c873ed3054",
    //          "Version": 0,
    //          "CreateTime": new Date(
    //          1322293883161
    //        )
    //      },
    //      {
    //          "Page": {
    //              "IconCss16": "role16",
    //              "IconCss24": "role24",
    //              "IconCss48": "role48",
    //              "IndexField": 0,
    //              "IsHide": false,
    //              "PageId": "/TestModule/Module2/Module2",
    //              "IsDisable": false,
    //              "Text": "测试模块二",
    //              "Parent": "faef4fe9-3c0e-4d9e-90e7-4b55b5280e87",
    //              "IsLeaf": true,
    //              "NodeLevel": 2,
    //              "Id": "d6007a2b-f903-44c7-ace5-7b22bf6d7940",
    //              "Version": 0,
    //              "CreateTime": new Date(
    //            1322293883161
    //          )
    //          },
    //          "PageId": "/TestModule/Module2/Module2",
    //          "IndexField": 0,
    //          "Id": "56e34069-fe27-4e96-acd2-920672aef980",
    //          "Version": 0,
    //          "CreateTime": new Date(
    //          1322293883161
    //        )
    //      }
    //    ],
    shortcuts: Ext.create('Ext.data.Store', {
        autoLoad: true,
        fields: [{
            name: 'Id'
        }, {
            name: 'Text',
            mapping: 'Page.Text'
        }, {
            name: 'IconCss48',
            mapping: 'Page.IconCss48'
        }, {
            name: 'PageId',
            mapping: 'Page.PageId'
        }],
        proxy: {
            type: 'ajax',
            url: 'facade.axd?s_action=GetCurrentUserShortcuts',
            reader: {
                type: 'json',
                root: ''
            }
        }

    }),

    /**
    * @cfg {String} shortcutItemSelector This property is passed to the
    *      DataView for the desktop to select shortcut items. If the
    *      {@link #shortcutTpl} is modified, this will probably need to be
    *      modified as well.
    */
    shortcutItemSelector: 'div.appButton',

    /**
    * @cfg {String} shortcutTpl This XTemplate is used to render items in the
    *      DataView. If this is changed, the {@link shortcutItemSelect} will
    *      probably also need to changed.
    */
    // shortcutTpl : ['<tpl for=".">',
    // '<div class="ux-desktop-shortcut" id="{name}-shortcut">',
    // '<div class="ux-desktop-shortcut-icon {iconCls}">', '<img src="',
    // Ext.BLANK_IMAGE_URL, '" title="{name}">', '</div>',
    // '<span class="ux-desktop-shortcut-text">{name}</span>', '</div>',
    // '</tpl>', '<div class="x-clear"></div>'],
    shortcutTpl: ['<tpl for=".">', '<div  class="appButton">',
			'<div class="appButton_appIcon {IconCss48}" ></div>',
			'  <div class="appButton_appName">',
			'<div  class="appButton_appName_inner">{Text}</div>', ' </div>',
			'</div>', '</tpl>'],

    /**
    * @cfg {Object} taskbarConfig The config object for the TaskBar.
    */
    taskbarConfig: null,

    windowMenu: null,

    initComponent: function () {
        var me = this;

        me.windowMenu = new Ext.menu.Menu(me.createWindowMenu());

        me.bbar = me.taskbar = new Ext.ux.desktop.TaskBar(me.taskbarConfig);
        me.taskbar.windowMenu = me.windowMenu;

        me.windows = new Ext.util.MixedCollection();

        me.contextMenu = new Ext.menu.Menu(me.createDesktopMenu());

        me.items = [{
            xtype: 'wallpaper',
            id: me.id + '_wallpaper'
        }, me.createDataView()];

        me.callParent();
        me.shortcutsView = Ext.getCmp('desktop_shortcut');
        me.shortcutsView.on('itemclick', me.onShortcutItemClick, me);

        var wallpaper = me.wallpaper;
        me.wallpaper = me.items.getAt(0);
        if (wallpaper) {
            me.setWallpaper(wallpaper, me.wallpaperStretch);
        }
    },

    afterRender: function () {
        var me = this;
        me.callParent();
        me.el.on('contextmenu', me.onDesktopMenu, me);
    },

    // ------------------------------------------------------
    // Overrideable configuration creation methods

    createDataView: function () {
        var me = this;
        var tpl = Ext.create('Ext.container.Container', {
            layout: {
                type: 'hbox',
                align: 'stretch'
            },
            items: [Ext.create('Ext.container.Container', {
                region: 'west',
                width: 600,
                frame: true,
                layout: 'fitall',
                // autoScroll : true,
                items: [{
                    id: 'desktop_shortcut',
                    xtype: 'dataview',
                    overItemCls: 'x-view-over',
                    trackOver: true,
                    itemSelector: me.shortcutItemSelector,
                    store: me.shortcuts,
                    tpl: new Ext.XTemplate(me.shortcutTpl)
                }]
            })]
        });
        return tpl;
    },

    createDesktopMenu: function () {
        var me = this, ret = {
            items: me.contextMenuItems || []
        };

        if (ret.items.length) {
            ret.items.push('-');
        }

        ret.items.push({
            text: '显示桌面',
            iconCls: 'mymac2',
            handler: me.showDesktop,
            scope: me
        }, '-', {
            text: '规则排列窗口',
            handler: me.tileWindows,
            scope: me,
            minWindows: 1
        }, {
            text: '固定大小排列窗口',
            handler: me.checkerboardWindows,
            scope: me,
            minWindows: 1
        }, {
            text: '按列平铺窗口',
            handler: me.snapFitWindows,
            scope: me,
            minWindows: 1

        }, {
            text: '按行平铺窗口',
            handler: me.snapFitVWindows,
            scope: me,
            minWindows: 1

        }, {
            text: '折叠窗口',
            handler: me.cascadeWindows,
            scope: me,
            minWindows: 1
        }, '-', {
            text: '关闭所有窗体',
            handler: me.closeAllWinows,
            iconCls: 'Close3',
            scope: me,
            minWindows: 1
        })

        return ret;
    },

    createWindowMenu: function () {
        var me = this;
        return {
            defaultAlign: 'br-tr',
            items: [{
                text: '恢复',
                handler: me.onWindowMenuRestore,
                scope: me
            }, {
                text: '最小化',
                handler: me.onWindowMenuMinimize,
                scope: me
            }, {
                text: '最大化',
                handler: me.onWindowMenuMaximize,
                scope: me
            }, '-', {
                text: '关闭',
                handler: me.onWindowMenuClose,
                scope: me
            }],
            listeners: {
                beforeshow: me.onWindowMenuBeforeShow,
                hide: me.onWindowMenuHide,
                scope: me
            }
        };
    },

    // ------------------------------------------------------
    // Event handler methods

    onDesktopMenu: function (e) {
        var me = this, menu = me.contextMenu;
        e.stopEvent();
        if (!menu.rendered) {
            menu.on('beforeshow', me.onDesktopMenuBeforeShow, me);
        }
        menu.showAt(e.getXY());
        menu.doConstrain();
    },

    onDesktopMenuBeforeShow: function (menu) {
        var me = this, count = me.windows.getCount();

        menu.items.each(function (item) {
            var min = item.minWindows || 0;
            item.setDisabled(count < min);
        });
    },

    onShortcutItemClick: function (dataView, record) {
        var me = this, module = me.app.getModule(record.data.PageId);
        //Kwan.Debug(me.app);
        createWindow(module, me.app);
    },

    onWindowClose: function (win) {
        var me = this;
        me.windows.remove(win);
        me.taskbar.removeTaskButton(win.taskButton);
        me.updateActiveWindow();
    },

    // ------------------------------------------------------
    // Window context menu handlers

    onWindowMenuBeforeShow: function (menu) {
        var items = menu.items.items, win = menu.theWin;
        items[0].setDisabled(win.maximized !== true && win.hidden !== true); // Restore
        items[1].setDisabled(win.minimized === true); // Minimize
        items[2].setDisabled(win.maximized === true || win.hidden === true); // Maximize
    },

    onWindowMenuClose: function () {
        var me = this, win = me.windowMenu.theWin;

        win.close();
    },

    onWindowMenuHide: function (menu) {
        menu.theWin = null;
    },

    onWindowMenuMaximize: function () {
        var me = this, win = me.windowMenu.theWin;

        win.maximize();
    },

    onWindowMenuMinimize: function () {
        var me = this, win = me.windowMenu.theWin;

        win.minimize();
    },

    onWindowMenuRestore: function () {
        var me = this, win = me.windowMenu.theWin;

        me.restoreWindow(win);
    },

    // ------------------------------------------------------
    // Dynamic (re)configuration methods

    getWallpaper: function () {
        return this.wallpaper.wallpaper;
    },

    setTickSize: function (xTickSize, yTickSize) {
        var me = this, xt = me.xTickSize = xTickSize, yt = me.yTickSize = (arguments.length > 1)
				? yTickSize
				: xt;

        me.windows.each(function (win) {
            var dd = win.dd, resizer = win.resizer;
            dd.xTickSize = xt;
            dd.yTickSize = yt;
            resizer.widthIncrement = xt;
            resizer.heightIncrement = yt;
        });
    },

    setWallpaper: function (wallpaper, stretch) {
        this.wallpaper.setWallpaper(wallpaper, stretch);
        return this;
    },

    // ------------------------------------------------------
    // Window management methods

    cascadeWindows: function () {
        var x = 0, y = 0, zmgr = this.getDesktopZIndexManager();

        zmgr.eachBottomUp(function (win) {
            if (win.isWindow && win.isVisible() && !win.maximized) {
                win.setPosition(x, y);
                x += 20;
                y += 20;
            }
        });
    },
    createWindow: function (config, cls) {
        if (!deskWidth) {
            deskWidth = Ext.getBody().getWidth();
            deskHeight = Ext.getBody().getHeight();
        }
        var me = this, winCount = me.windows.getCount();
        if (winCount >= 5) {
            Ext.MessageBox.show({
                title: '系统提示',
                msg: '为保证系统效率,只允许同时运行5个功能窗口.请关闭一些窗口后重试',
                buttons: Ext.MessageBox.OK,
                icon: Ext.MessageBox.WARNING
            });
            return;
        }
        var win, cfg = Ext.applyIf(config || {}, {
            //width: 950, height: 580,
            width: deskWidth - 260, height: deskHeight - 120,
            stateful: false,
            isWindow: true,
            // constrainHeader : true,
            minimizable: true,
            maximizable: true
        });
        //Kwan.Debug(cfg);
        cls = cls || Ext.window.Window;
        //Kwan.Debug(cfg);
        win = me.add(new cls(cfg));

        me.windows.add(win);

        win.taskButton = me.taskbar.addTaskButton(win);
        // win.animateTarget = win.taskButton.el;关闭打开的渐变 免得卡

        win.on({
            activate: me.updateActiveWindow,
            beforeshow: me.updateActiveWindow,
            deactivate: me.updateActiveWindow,
            minimize: me.minimizeWindow,
            destroy: me.onWindowClose,
            scope: me
        });

        win.on({
            afterrender: function () {
                win.dd.xTickSize = me.xTickSize;
                win.dd.yTickSize = me.yTickSize;

                if (win.resizer) {
                    win.resizer.widthIncrement = me.xTickSize;
                    win.resizer.heightIncrement = me.yTickSize;
                }
            },
            single: true
        });

        // replace normal window close w/fadeOut animation:
        win.doClose = function () {
            win.el.disableShadow();
            win.el.fadeOut({
                listeners: {
                    afteranimate: function () {
                        win.destroy();
                    }
                }
            });
        };

        return win;
    },

    getActiveWindow: function () {
        var win = null, zmgr = this.getDesktopZIndexManager();

        if (zmgr) {
            // We cannot rely on activate/deactive because that fires against
            // non-Window
            // components in the stack.

            zmgr.eachTopDown(function (comp) {
                if (comp.isWindow && !comp.hidden) {
                    win = comp;
                    return false;
                }
                return true;
            });
        }

        return win;
    },

    getDesktopZIndexManager: function () {
        var windows = this.windows;
        // TODO - there has to be a better way to get this...
        return (windows.getCount() && windows.getAt(0).zIndexManager) || null;
    },

    getWindow: function (id) {
        return this.windows.get(id);
    },

    minimizeWindow: function (win) {
        win.minimized = true;
        win.hide();
    },

    restoreWindow: function (win) {
        if (win.isVisible()) {
            win.restore();
            win.toFront();
        } else {
            win.show();
        }
        return win;
    },

    showDesktop: function () {
        var me = this;
        me.windows.each(function (win) {
            if (!win.minimized) {
                win.minimize();
            }
        });
    },
    closeAllWinows: function () {
        var me = this, winCount = me.windows.getCount();
        if (winCount < 1)
            return;
        Ext.MessageBox.confirm('操作确认', '确定要关闭当前所有窗口吗?', function (btn) {
            if (btn == 'yes') {
                var me = this;
                me.windows.each(function (win) {
                    win.close();
                });
            }
        }, this);
    },
    snapFitVWindows: function () {
        var me = this;
        var availWidth = this.el.getWidth(true);
        var availHeight = this.el.getHeight(true) - 40;

        var x = 0, y = 0;

        // How to get number of windows?
        // var snapCount = windows.length;
        var snapCount = 0;

        this.windows.each(function (win) {
            if (win.isVisible()) {
                snapCount++;
            }
        }, this);
        // above loop seems unnecessary?

        var snapSize = parseInt(availHeight / snapCount);

        if (snapSize > 0) {
            this.windows.each(function (win) {
                if (win.isVisible()) {
                    // Subtract 10 for padding?
                    win.setWidth(availWidth);
                    win.setHeight(snapSize);

                    win.setPosition(x, y);
                    y += snapSize;
                }
            }, me);
        }
    },
    snapFitWindows: function () {
        var me = this;
        var availWidth = this.el.getWidth(true);
        var availHeight = this.el.getHeight(true) - 40;

        var x = 0, y = 0;

        // How to get number of windows?
        // var snapCount = windows.length;
        var snapCount = 0;

        this.windows.each(function (win) {
            if (win.isVisible()) {
                snapCount++;
            }
        }, this);
        // above loop seems unnecessary?

        var snapSize = parseInt(availWidth / snapCount);

        if (snapSize > 0) {
            this.windows.each(function (win) {
                if (win.isVisible()) {
                    // Subtract 10 for padding?
                    win.setWidth(snapSize);
                    win.setHeight(availHeight);

                    win.setPosition(x, y);
                    x += snapSize;
                }
            }, me);
        }
    },
    checkerboardWindows: function () {
        var me = this;
        var availWidth = this.el.getWidth(true);
        var availHeight = this.el.getHeight(true) - 40;

        var x = 0, y = 0;
        var lastx = 0, lasty = 0;

        // square size should be a value set user?
        var square = 400;

        this.windows.each(function (win) {
            // if (win.isVisible() && !win.maximized) {
            if (win.isVisible()) {
                // Subtract padding, should be a value set user?
                win.setWidth(square - 1);
                win.setHeight(square - 1);

                win.setPosition(x, y);
                x += square;

                if (x + square > availWidth) {
                    x = lastx;
                    y += square;

                    if (y > availHeight) {
                        lastx += 20;
                        lasty += 20;
                        x = lastx;
                        y = lasty;
                    }
                }
            }
        }, me);
    },
    tileWindows: function () {
        var me = this, availWidth = me.body.getWidth(true);
        var x = me.xTickSize, y = me.yTickSize, nextY = y;

        me.windows.each(function (win) {
            if (win.isVisible() && !win.maximized) {
                var w = win.el.getWidth();

                // Wrap to next row if we are not at the line start and
                // this Window will
                // go off the end
                if (x > me.xTickSize && x + w > availWidth) {
                    x = me.xTickSize;
                    y = nextY;
                }

                win.setPosition(x, y);
                x += w + me.xTickSize;
                nextY = Math.max(nextY, y + win.el.getHeight()
										+ me.yTickSize);
            }
        });
    },

    updateActiveWindow: function () {
        var me = this, winCount = me.windows.getCount();
        var activeWindow = me.getActiveWindow(), last = me.lastActiveWindow;
        if (activeWindow === last) {
            return;
        }

        if (last) {
            if (last.el.dom) {
                last.addCls(me.inactiveWindowCls);
                last.removeCls(me.activeWindowCls);
            }
            last.active = false;
        }

        me.lastActiveWindow = activeWindow;

        if (activeWindow) {
            activeWindow.addCls(me.activeWindowCls);
            activeWindow.removeCls(me.inactiveWindowCls);
            activeWindow.minimized = false;
            activeWindow.active = true;
        }

        me.taskbar.setActiveButton(activeWindow && activeWindow.taskButton);
    }
});
